part of '../repository.dart';

const _kBackupCustomLexicalItemKey = 'custom_lexical_items';
const _kBackupLexicalItemMetaMapKey = 'lexical_item_meta_map';
const _kBackupCustomCollectionListItemKey = 'custom_collection_list_items';
const _kBackupCollectionMetaMapKey = 'collection_meta_map';
const _kBackupTopLevelCollectionListItemIdKey = 'top_level_collection_list_item_ids';
const _kBackupLearningInfoKey = 'learning_info';

class _BackupDto extends Equatable {
  const _BackupDto._internal({
    required this.customLexicalItemDtos,
    required this.lexicalItemMetaDtoMap,
    required this.customCollectionListItemDtos,
    required this.collectionMetaDtoMap,
    required this.topLevelCollectionListItemIds,
    required this.learningInfoDto,
  });

  final BuiltList<_CustomLexicalItemDataDto> customLexicalItemDtos;
  final BuiltMap<String, _LexicalItemMetaDto> lexicalItemMetaDtoMap;
  final BuiltList<_CustomCollectionListItemDataDto> customCollectionListItemDtos;
  final BuiltMap<String, _CollectionMetaDto> collectionMetaDtoMap;
  final BuiltList<String> topLevelCollectionListItemIds;
  final _LearningInfoDto learningInfoDto;

  @override
  List<Object?> get props {
    return [
      customLexicalItemDtos,
      lexicalItemMetaDtoMap,
      customCollectionListItemDtos,
      collectionMetaDtoMap,
      topLevelCollectionListItemIds,
      learningInfoDto,
    ];
  }

  factory _BackupDto.fromJson(Map<String, dynamic> json) {
    // customLexicalItems

    final customLexicalItemMaps = List.castFrom<dynamic, Map>(json[_kBackupCustomLexicalItemKey]);

    final customLexicalItemDtos = customLexicalItemMaps.map((customLexicalItemMap) {
      final customLexicalItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(customLexicalItemMap);

      return _CustomLexicalItemDataDto.fromJson(customLexicalItemJson);
    }).toBuiltList();

    // lexicalItemMetaMap

    final lexicalItemMetaMap = Map.castFrom(json[_kBackupLexicalItemMetaMapKey]);

    final lexicalItemMetaDtoMap = lexicalItemMetaMap.map((lexicalItemId, value) {
      final singleLexicalItemMetaJson = Map.castFrom<dynamic, dynamic, String, dynamic>(value);
      final lexicalItemMetaDto = _LexicalItemMetaDto.fromJson(singleLexicalItemMetaJson);

      return MapEntry(lexicalItemId as String, lexicalItemMetaDto);
    }).build();

    // customCollectionListItems

    final customCollectionListItemMaps =
        List.castFrom<dynamic, Map>(json[_kBackupCustomCollectionListItemKey]);

    final customCollectionListItemDtos =
        customCollectionListItemMaps.map((customCollectionListItemMap) {
      final customCollectionListItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(customCollectionListItemMap);

      return _CustomCollectionListItemDataDtoFactory().fromJson(customCollectionListItemJson);
    }).toBuiltList();

    // collectionMetaMap

    final collectionMetaMap = Map.castFrom(json[_kBackupCollectionMetaMapKey]);

    final collectionMetaDtoMap = collectionMetaMap.map((collectionId, value) {
      final singleCollectionMetaJson = Map.castFrom<dynamic, dynamic, String, dynamic>(value);
      final collectionMetaDto = _CollectionMetaDto.fromJson(singleCollectionMetaJson);

      return MapEntry(collectionId as String, collectionMetaDto);
    }).build();

    // topLevelCollectionListItemIds

    final topLevelCollectionListItemIds =
        List.castFrom<dynamic, String>(json[_kBackupTopLevelCollectionListItemIdKey]).toBuiltList();

    // learning info

    final learningInfoJson =
        Map.castFrom<dynamic, dynamic, String, dynamic>(json[_kBackupLearningInfoKey]);
    final learningInfoDto = _LearningInfoDto.fromJson(learningInfoJson);

    return _BackupDto._internal(
      customLexicalItemDtos: customLexicalItemDtos,
      lexicalItemMetaDtoMap: lexicalItemMetaDtoMap,
      customCollectionListItemDtos: customCollectionListItemDtos,
      collectionMetaDtoMap: collectionMetaDtoMap,
      topLevelCollectionListItemIds: topLevelCollectionListItemIds,
      learningInfoDto: learningInfoDto,
    );
  }

  factory _BackupDto.fromEntity(Backup backup) {
    final customLexicalItemDtos = backup.customLexicalItemDataList.map((customLexicalItem) {
      return _CustomLexicalItemDataDto.fromEntity(customLexicalItem);
    }).toBuiltList();

    final lexicalItemMetaDtoMap = backup.lexicalItemMetaMap.map((lexicalItemId, lexicalItemMeta) {
      final lexicalItemMetaDto = _LexicalItemMetaDto.fromLexicalItemMeta(lexicalItemMeta);

      return MapEntry(lexicalItemId, lexicalItemMetaDto);
    });

    final customCollectionListItemDtos =
        backup.customCollectionListItemDataList.map((customCollectionListItem) {
      return _CustomCollectionListItemDataDtoFactory().fromEntity(customCollectionListItem);
    }).toBuiltList();

    final collectionMetaDtoMap = backup.collectionMetaMap.map((collectionId, collectionMeta) {
      final collectionMetaDto = _CollectionMetaDto.fromEntity(collectionMeta);

      return MapEntry(collectionId, collectionMetaDto);
    });

    final learningInfoDto = _LearningInfoDto.fromEntity(backup.learningInfo);

    return _BackupDto._internal(
      customLexicalItemDtos: customLexicalItemDtos,
      lexicalItemMetaDtoMap: lexicalItemMetaDtoMap,
      customCollectionListItemDtos: customCollectionListItemDtos,
      collectionMetaDtoMap: collectionMetaDtoMap,
      topLevelCollectionListItemIds: backup.topLevelCollectionListItemIds,
      learningInfoDto: learningInfoDto,
    );
  }

  Map<String, dynamic> toJson() {
    final customLexicalItemJsons = customLexicalItemDtos.map((customLexicalItemDto) {
      return customLexicalItemDto.toJson();
    }).toList();

    final lexicalItemMetaJson = lexicalItemMetaDtoMap.map((lexicalItemId, lexicalItemMetaDto) {
      final singleLexicalItemMetaJson = lexicalItemMetaDto.toJson();

      return MapEntry(lexicalItemId, singleLexicalItemMetaJson);
    }).toMap();

    final customCollectionListItemJsons =
        customCollectionListItemDtos.map((customCollectionListItemDto) {
      return customCollectionListItemDto.toJson();
    }).toList();

    final collectionMetaJson = collectionMetaDtoMap.map((collectionId, collectionMetaDto) {
      final singleCollectionMetaJson = collectionMetaDto.toJson();

      return MapEntry(collectionId, singleCollectionMetaJson);
    }).toMap();

    final learningInfoJson = learningInfoDto.toJson();

    return {
      _kBackupCustomLexicalItemKey: customLexicalItemJsons,
      _kBackupLexicalItemMetaMapKey: lexicalItemMetaJson,
      _kBackupCustomCollectionListItemKey: customCollectionListItemJsons,
      _kBackupCollectionMetaMapKey: collectionMetaJson,
      _kBackupTopLevelCollectionListItemIdKey: topLevelCollectionListItemIds.toList(),
      _kBackupLearningInfoKey: learningInfoJson,
    };
  }

  Backup toEntity() {
    final customLexicalItems = customLexicalItemDtos.map((customLexicalItemDto) {
      return customLexicalItemDto.toEntity();
    }).toBuiltList();

    final lexicalItemMetaMap = lexicalItemMetaDtoMap.map((lexicalItemId, lexicalItemMetaDto) {
      final lexicalItemMeta = lexicalItemMetaDto.toEntity();

      return MapEntry(lexicalItemId, lexicalItemMeta);
    });

    final customCollectionListItems =
        customCollectionListItemDtos.map((customCollectionListItemDto) {
      return customCollectionListItemDto.toEntity();
    }).toBuiltList();

    final collectionMetaMap = collectionMetaDtoMap.map((collectionId, collectionMetaDto) {
      final collectionMeta = collectionMetaDto.toEntity();

      return MapEntry(collectionId, collectionMeta);
    });

    final learningInfo = learningInfoDto.toEntity();

    return Backup(
      customLexicalItemDataList: customLexicalItems,
      lexicalItemMetaMap: lexicalItemMetaMap,
      topLevelCollectionListItemIds: topLevelCollectionListItemIds,
      customCollectionListItemDataList: customCollectionListItems,
      collectionMetaMap: collectionMetaMap,
      learningInfo: learningInfo,
    );
  }
}
